#include "ServerTcp.hpp"

int ServerTcp::CheckIsComplete(Connected &co,
			       int fd)
{
  return ACommunicator::CheckIsComplete(co, fd);
}

int	ServerTcp::TryToWrite(std::list<Buffer *> &writeBuf,
			      int fd)
{
  return ACommunicator::TryToWrite(writeBuf, fd);
}

int	ServerTcp::TryToRead(Buffer &readBuf,
			     int fd)
{
  return ACommunicator::TryToRead(readBuf, fd);
}

int	ServerTcp::CheckCompleteBuf()
{
  std::list<Connected *>::iterator              it;

  Ctl.GetBuf().SetBuffer(NULL);
  if (!Co.empty())
    for (it = Co.begin(); it != Co.end(); ++it)
      {
	Connected	&co = *(*it);

	if (CheckIsComplete(co, co.GetFd()) == 0)
	  return (0);
      }
  return (1);
}

int	ServerTcp::Network()
{
  int            fdMax;

  Ctl.SetVal(Control::DEFAULT);
  Tim.InitTim();
  if (CheckCompleteBuf() == 0)
    return (0);
  fdMax =  FdInfo.InitFdServer(FdSocket, Co);
  if (Tcp->Select(fdMax + 1, FdInfo, Tim) == -1)
    return (-1);
  if (Tim.GetTvUsec() == 0 && Tim.GetTvSec() == 0)
    return (0);
  if (FdInfo.FdIsset(FdSocket, FdInfo.GetReadf()))
    {
      if (NewConnection() == -1)
        return (-1);
      return (0);
    }
  if (ReadOrWrite() == -1)
    return (-1);
  return (0);

}

int	ServerTcp::ReadOrWrite()
{
  std::list<Connected *>::iterator  it;
  int                   ret;

  if (!Co.empty())
    {
      it = Co.begin();
      while (it != Co.end())
	{
	  if (FdInfo.FdIsset((*it)->GetFd(), FdInfo.GetReadf()))
	    if ((ret = TryToRead((*it)->GetReadBuf(), (*it)->GetFd())) <= 0)
	      return (ret);
	  if (FdInfo.FdIsset((*it)->GetFd(), FdInfo.GetWritef()))
	    if ((ret = TryToWrite( (*it)->GetWriteBuf(), (*it)->GetFd())) <= 0)
	      return (ret);
	  it++;
	}
    }
  return (1);
}

int	ServerTcp::NewConnection()
{
  SockInfo   si(Port);
  Connected   *co;
  int		ret;
  
  si.InitTcpSiSr();
  co = new Connected;
  if ((ret = Tcp->Accept(FdSocket, si)) == -1)
    return (-1);
  co->SetFd(ret);
  co->GetReadBuf().SetBuffer(NULL);
  co->GetReadBuf().SetBufferSize(0);
  co->GetReadBuf().SetAlreadyRead(-1);
  Ctl.SetVal(Control::NEW_CONNECTION);
  Ctl.SetFd(co->GetFd());
  Ctl.GetBuf().SetAlreadyRead(0);
  Co.push_back(co);
  return (0);
}

int	ServerTcp::Add_A_Connected()
{
  Connected   *co;

  co = new Connected;
  Co.push_back(co);
  return (0);
}

int	ServerTcp::Remove_A_Connected()
{
  Co.pop_front();
  return (0);
}

int	ServerTcp::Connection()
{
  SockInfo    si(Port);

  si.InitTcpSiSr();
  if (Tcp->Bind(FdSocket, si) == -1)
    {
      puts("Can't bind local socket.\n");
      return (-1);
    }
  if (Tcp->Listen(FdSocket) == -1)
    {
      puts("Network not available.\n");
      return (-1);
    }
  puts("Server connected.");
  return (0);
}

ServerTcp::ServerTcp(int	port)
: ACommunicator(port)
{
  Tcp->OpenSocket(FdSocket);
  Connection();
}

ServerTcp::~ServerTcp()
{
}

int	ServerTcp::Run()
{
  std::list<Connected *>::iterator it;

  it = Co.begin();
  while (Network() != -1)
    if (Ctl.GetVal() == Control::NEW_CONNECTION)
      AddToListWrite(Ctl.GetFd(), (char*)"Ping", 5);
    else if (Ctl.GetVal() == Control::DISCONNECTED)
      {
	printf("Client %d disconnected.\n", Ctl.GetFd());
	if (Remove_A_Connected() == -1)
	  return -1;
      }
    else if (Ctl.GetVal() == Control::BUF_COMPLETE)
      {
	puts(Ctl.GetBuf().GetBuffer());
	AddToListWrite(Ctl.GetFd(), (char*)"Ping", 5);
	free(Ctl.GetBuf().GetBuffer());
      }
  return 0;
}

int   ServerTcp::AddToListWrite(int fd,
				char *buf,
				int sizeBuf)
{
  std::list<Connected *>::iterator it;

  if (!Co.empty())
    {
      it = Co.begin();
      while (it != Co.end())
	{
	  if ((*it)->GetFd() == fd)
	    {
	      if ((*it)->AddListWrite(buf, sizeBuf) == -1)
		return -1;
	      return 0;
	    }
	  it++;
	}
    }
  return -1;
}

int ServerTcp::TraitementBuf()
{
  return ACommunicator::TraitementBuf();
}
